﻿#include "FileNameValidator.h"
#include <QRegularExpression>
#include <QDebug>

FileNameValidator::FileNameValidator()
{
    initializeInvalidChars();
}

void FileNameValidator::initializeInvalidChars()
{
    m_invalidChars.clear();
    m_reservedNames.clear();

#ifdef CURRENT_OS_WINDOWS
    // Windows 非法字符
    m_invalidChars = {'<', '>', ':', '"', '/', '\\', '|', '?', '*'};

    // Windows 保留名称
    m_reservedNames = {
        "CON", "PRN", "AUX", "NUL",
        "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
        "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"
    };

#elif defined(CURRENT_OS_MACOS)
    // macOS 非法字符 (主要是冒号，现代系统也避免其他字符)
    m_invalidChars = {':', '/', '\0'};

#elif defined(CURRENT_OS_LINUX) || defined(CURRENT_OS_UNIX)
    // Linux/Unix 非法字符
    m_invalidChars = {'/', '\0'};

#endif

    // 所有平台都应避免的控制字符 (0x00-0x1F, 0x7F)
    for (int i = 0; i <= 0x1F; ++i) {
        m_invalidChars.insert(QChar(i));
    }
    m_invalidChars.insert(QChar(0x7F)); // DEL字符
}

bool FileNameValidator::isValid(const QString &fileName, QString &errorMessage) const
{
    // 基本检查 - 所有平台通用
    if (fileName.isEmpty()) {
        errorMessage = QObject::tr("The file name cannot be empty");
        return false;
    }

    if (fileName.length() > 255) {
        errorMessage = QObject::tr("The file name is too long (maximum 255 characters)");
        return false;
    }

    // 检查开头和结尾字符
    if (fileName.startsWith(' ') || fileName.startsWith('.') ||
        fileName.endsWith(' ') || fileName.endsWith('.')) {
        errorMessage = QObject::tr("The file name cannot start/end with a space or dot");
        return false;
    }

    // 平台特定验证
#ifdef CURRENT_OS_WINDOWS
    return validateWindows(fileName, errorMessage);
#elif defined(CURRENT_OS_MACOS)
    return validateMacOS(fileName, errorMessage);
#else
    return validateUnixLike(fileName, errorMessage);
#endif
}

bool FileNameValidator::validateWindows(const QString &fileName, QString &errorMessage) const
{
    // 检查非法字符
    for (const QChar &c : fileName) {
        if (m_invalidChars.contains(c)) {
            errorMessage = QObject::tr("The file name contains illegal characters: '%1'").arg(c);
            return false;
        }
    }

    // 检查保留名称
    QString upperName = fileName.toUpper();
    if (m_reservedNames.contains(upperName)) {
        errorMessage = QObject::tr("The file name is a system reserved name");
        return false;
    }

    // 检查文件名格式（不能以点号结尾等）
    if (fileName.endsWith(".")) {
        errorMessage = QObject::tr("The file name cannot end with a dot");
        return false;
    }

    return true;
}

bool FileNameValidator::validateUnixLike(const QString &fileName, QString &errorMessage) const
{
    // Unix/Linux 验证
    for (const QChar &c : fileName) {
        if (m_invalidChars.contains(c)) {
            errorMessage = QObject::tr("The file name contains illegal characters: '%1'").arg(c);
            return false;
        }
    }

    // 检查是否包含路径分隔符
    if (fileName.contains('/')) {
        errorMessage = QObject::tr("The file name cannot contain the path delimiter '/'");
        return false;
    }

    return true;
}

bool FileNameValidator::validateMacOS(const QString &fileName, QString &errorMessage) const
{
    // macOS 验证（基于Unix，但有额外限制）
    for (const QChar &c : fileName) {
        if (m_invalidChars.contains(c)) {
            errorMessage = QObject::tr("The file name contains illegal characters: '%1'").arg(c);
            return false;
        }
    }

    // 检查冒号（历史遗留问题）
    if (fileName.contains(':')) {
        errorMessage = QObject::tr("The file name cannot contain a colon");
        return false;
    }

    return true;
}

QString FileNameValidator::sanitize(const QString &fileName) const
{
    if (fileName.isEmpty()) {
        return "unnamed_file";
    }

#ifdef CURRENT_OS_WINDOWS
    return sanitizeWindows(fileName);
#elif defined(CURRENT_OS_MACOS)
    return sanitizeMacOS(fileName);
#else
    return sanitizeUnixLike(fileName);
#endif
}

QString FileNameValidator::sanitizeWindows(const QString &fileName) const
{
    QString cleanName = fileName;

    // 移除Windows非法字符
    for (const QChar &invalidChar : m_invalidChars) {
        cleanName.remove(invalidChar);
    }

    // 移除控制字符
    cleanName.remove(QRegularExpression("[\\x00-\\x1F\\x7F]"));

    // 替换多个连续点号或空格
    cleanName.replace(QRegularExpression("\\.{2,}"), ".");
    cleanName.replace(QRegularExpression(" {2,}"), " ");

    // 修剪开头和结尾的空格和点号
    cleanName = cleanName.trimmed();
    while (cleanName.endsWith('.')) {
        cleanName.chop(1);
    }

    // 检查是否为保留名称
    QString upperName = cleanName.toUpper();
    if (m_reservedNames.contains(upperName)) {
        cleanName = "file_" + cleanName;
    }

    // 长度限制
    if (cleanName.length() > 255) {
        cleanName = cleanName.left(255);
    }

    if (cleanName.isEmpty()) {
        cleanName = "unnamed_file";
    }

    return cleanName;
}

QString FileNameValidator::sanitizeUnixLike(const QString &fileName) const
{
    QString cleanName = fileName;

    // 移除非法字符
    for (const QChar &invalidChar : m_invalidChars) {
        cleanName.remove(invalidChar);
    }

    // 移除控制字符
    cleanName.remove(QRegularExpression("[\\x00-\\x1F\\x7F]"));

    // 修剪空格
    cleanName = cleanName.trimmed();

    // 长度限制
    if (cleanName.length() > 255) {
        cleanName = cleanName.left(255);
    }

    if (cleanName.isEmpty()) {
        cleanName = "unnamed_file";
    }

    return cleanName;
}

QString FileNameValidator::sanitizeMacOS(const QString &fileName) const
{
    QString cleanName = fileName;

    // 移除macOS非法字符
    for (const QChar &invalidChar : m_invalidChars) {
        cleanName.remove(invalidChar);
    }

    // 特别处理冒号
    cleanName.remove(':');

    // 移除控制字符
    cleanName.remove(QRegularExpression("[\\x00-\\x1F\\x7F]"));

    // 修剪空格
    cleanName = cleanName.trimmed();

    // 长度限制
    if (cleanName.length() > 255) {
        cleanName = cleanName.left(255);
    }

    if (cleanName.isEmpty()) {
        cleanName = "unnamed_file";
    }

    return cleanName;
}

QString FileNameValidator::currentPlatform()
{
#ifdef CURRENT_OS_WINDOWS
    return "Windows";
#elif defined(CURRENT_OS_MACOS)
    return "macOS";
#elif defined(CURRENT_OS_LINUX)
    return "Linux";
#elif defined(CURRENT_OS_UNIX)
    return "Unix";
#else
    return "Unknown";
#endif
}
